--[[
/*
 * @Descripttion: 
 * @version: 
 * @Author: jiuguo.qin
 * @Date: 2020-02-09 12:16:52
 * @LastEditors: jiuguo.qin
 * @LastEditTime: 2020-05-05 21:18:46
 */
]]

local ffi = require "ffi"
local cjson = require "cjson.safe"
ffi.cdef[[
#pragma pack(8)
typedef struct{   
    uint32_t  	length:32;
	uint32_t 	taskid:32;
    uint16_t    magic:16;
    uint8_t  	command:8;
    uint8_t		is_force:8;
    char        name[64];
}wrk_packet_head_t;
#pragma pack()  

uint32_t ntohl(uint32_t netlong);
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t s);
]]

local _M = {
    _VERSION = 0.1,
    _magic   = 2020,
    _CMD = {
        start = 1,
        stop  = 2,
        stats = 3,
        upload = 4
    }
}

function _M:new(host, port)
    self.host = host
    self.port = port
    self.__index = self

    local sock = ngx.socket.tcp()
    local ok, err = sock:connect(host, port)
    sock:settimeout(0)
    if err then 
        ngx.log(ngx.ERR, err)
        ngx.exit(200)
    end

    self.sock = sock

    return _M
end

-- {taskid=taskid, is_force=is_force, command=cmd, payload=body}
function _M:send(data)
    local taskid = data.taskid
    local command = data.command
    local force = data.is_force
    local payload = data.payload
    local head = ffi.new("wrk_packet_head_t", ffi.sizeof("wrk_packet_head_t"))
    
    head.taskid = ffi.C.htonl(taskid)
    head.magic  = ffi.C.htons(self._magic)
    head.is_force =  force;

    -- command is string, cmd name,eg: start, stats, stop, upload
    head.name     = command;
    head.command  = self._CMD[command] 
    head.length = ffi.C.htonl(#payload)

    local d = ffi.string(head, ffi.sizeof("wrk_packet_head_t"))..payload
    local bytes, err = self.sock:send(d)
    if err then
        ngx.log(ngx.ERR, err)
        ngx.exit(200)
    end
    
    return bytes
end

function _M:receive()
    local line, err, partial = self.sock:receive("*l")
    if err then
        ngx.log(ngx.ERR, err)
        ngx.exit(200)
    end

    self.sock:close()

    -- print(line)
    return cjson.decode(line)
    -- return line
end

return _M


